package com.mew.chess.core.game.pokdeng.game.core;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.mew.chess.core.common.handler.ChessPushMessageUtil;
import com.mew.chess.core.game.pokdeng.game.*;
import com.mew.chess.core.game.pokdeng.game.common.PokDengConstantValue;
import com.mew.chess.core.game.pokdeng.game.common.PokDengLinkType;
import com.mew.chess.core.game.pokdeng.game.common.PokDengPushCMDMapType;
import com.mew.chess.core.game.pokdeng.game.message.CardMessage;
import com.mew.chess.core.game.pokdeng.game.message.PushOtherAskCardMessage;
import com.mew.chess.core.game.pokdeng.game.message.UserMessage;
import com.mew.common.enm.UserType;
import com.mew.common.entity.config.Room;
import com.mew.common.rest.bo.GameSession;
import com.zebra.common.concurrent.ZebraExecutorManager;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;

import java.util.*;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;

/**
 * @author dylin
 * @create 2021/4/29
 */
@Component
@Slf4j
public class TableUtil {
    private static int maxTableID=0;
    /**
     * 初始化桌子
     * @param room
     * @return
     */
    public static PokDengTableManager initializeTable(Room room){
        maxTableID++;
        PokDengTableManager tableManager=new PokDengTableManager(maxTableID);
        tableManager.setBetStrs(room.getBetArrs());
        tableManager.setBetArrays(StrUtil.splitToInt(room.getBetArrs(), ","));
        tableManager.setMinGoldNumber(room.getMinGoldNumber());
        tableManager.setOverTime(PokDengConstantValue.OVER_TIME);

        tableManager.setLinkType(PokDengLinkType.Prepare.code());
        tableManager.setRuleTime(PokDengConstantValue.PREPARE_TIME);
        tableManager.setScheduleManager(new PokDengScheduleManager(room.getId(),maxTableID, ZebraExecutorManager.getInstance().getDefaultScheduler(), ZebraExecutorManager.getInstance().getDefaultExecutor()));
        UserMessage banker=new UserMessage();
        banker.setGameSession(new GameSession());
        tableManager.setBanker(PokDengSeatManager.builder().seatNo(-1).user(banker).build());
        return tableManager;
    }

    /**
     * 克隆一张桌子
     */
    public static PokDengTableManager cloneTable(PokDengTableManager tableManager,int roomId){
        maxTableID++;
        PokDengTableManager cloneTableManager=new PokDengTableManager(maxTableID);
        cloneTableManager.setBetStrs(tableManager.getBetStrs());
        cloneTableManager.setBetArrays(tableManager.getBetArrays());
        cloneTableManager.setMinGoldNumber(tableManager.getMinGoldNumber());
        cloneTableManager.setOverTime(PokDengConstantValue.OVER_TIME);

        cloneTableManager.setLinkType(PokDengLinkType.Prepare.code());
        cloneTableManager.setRuleTime(PokDengConstantValue.PREPARE_TIME);
        cloneTableManager.setScheduleManager(new PokDengScheduleManager(roomId,maxTableID, ZebraExecutorManager.getInstance().getDefaultScheduler(), ZebraExecutorManager.getInstance().getDefaultExecutor()));
        UserMessage banker=new UserMessage();
        banker.setGameSession(new GameSession());
        tableManager.setBanker(PokDengSeatManager.builder().seatNo(-1).user(banker).build());
        return cloneTableManager;
    }
    /**
     * 桌子 坐下
     */
    public static PokDengSeatManager entityRoomSitDownRecursion(PokDengRoomManager roomManager,UserMessage user){
        Map<Integer,List<Integer>> emptyTable= roomManager.getEmptyTable();
        if (null == emptyTable || emptyTable.isEmpty()
                ||computeSeatFACTOR(roomManager,emptyTable)){
            //增加桌子
            for (int i = 0; i < PokDengConstantValue.TABLE_AUTO_INC; i++) {
                PokDengTableManager cloneTable=cloneTable(roomManager.getTableMangerMap().values().iterator().next(),roomManager.getRoomId());
                roomManager.putTableManger(cloneTable);
            }
            emptyTable= roomManager.getEmptyTable();
        }
        List<Integer> emptyTableIds = emptyTable.keySet().stream().collect(Collectors.toList());
        int tableId=emptyTableIds.get(RandomUtil.randomInt(emptyTableIds.size()));
        List<Integer> emptySeats=emptyTable.get(tableId);
        int seatNo=emptySeats.get(RandomUtil.randomInt(emptySeats.size()));
        user.setTableId(tableId);
        user.setSeatNo((byte) seatNo);
        PokDengSeatManager seat=sitDown(roomManager,tableId,seatNo,user,roomManager.getTableManager(tableId).getSemaphore());
        if(seat==null){
            return entityRoomSitDownRecursion(roomManager,user);
        }
        return seat;
    }

    /**
     * 机器人坐下
     * @return
     */
    private static PokDengSeatManager robotRoomSitDownRecursion(PokDengRoomManager roomManager,int tableId,UserMessage robot){
        List<Integer> emptySeats=roomManager.getTableManager(tableId).getEmptySeat();
        if(null==emptySeats||emptySeats.isEmpty()){
            return null;
        }
        //空位数过少  机器人禁止进入
        if(emptySeats.size()<PokDengConstantValue.ROBOT_ENTER_WITH_EMPTY_SEAT){
            return null;
        }
        int seatNo=emptySeats.get(RandomUtil.randomInt(emptySeats.size()));
        robot.setTableId(tableId);
        robot.setSeatNo((byte) seatNo);
        PokDengSeatManager seat=sitDown(roomManager,tableId,seatNo,robot,roomManager.getTableManager(tableId).getSemaphore());
        //位置被别人占了 就不坐了
        if(seat==null){
            return null;
        }
        return seat;
    }

    private static PokDengSeatManager sitDown(PokDengRoomManager roomManager,int tableId,int seatNo, UserMessage user, Semaphore semaphore){
        try {
            semaphore.acquire();
            PokDengSeatManager seat = roomManager.getTableManager(tableId).getPokDengSeatManager(seatNo);
            if(seat.getUser()!=null){
                log.info("Player seat is down：userId {}， seatInfo {}", user.getUserId(), seat.toString());
                return null;
            }
            seat.setUser(user);
            log.info("Player seat：userId {}， seatInfo {}", user.getUserId(), seat.toString());
            return seat;
        }catch (Exception e){
            log.error("Player seat Error：", e);
        }finally {
            semaphore.release();
        }
        return null;
    }

    /**
     * 桌子负载因子决定要不要扩容
     * @return
     */
    private static boolean computeSeatFACTOR(PokDengRoomManager roomManager,Map<Integer,List<Integer>> emptyTable){
        //所有的座位数量
        int allSeatNumber=roomManager.getTableMangerMap().size()*PokDengConstantValue.MAX_SEAT;
        //空位置
        int emptySeatNumber=0;
        for (List<Integer> seat : emptyTable.values()) {
            emptySeatNumber+=seat.size();
        }
        //负载量
        int factorSeat=(int)(allSeatNumber*(1-PokDengConstantValue.TABLE_DEFAULT_LOAD_FACTOR));
        return emptySeatNumber<factorSeat;
    }

    public static Iterator<PokDengSeatManager> buildSeatIterator(int roomId,int tableId){
        PokDengTableManager table = PokDengGameManager.getInstance().getController(roomId).getTableManager(tableId);
        ConcurrentMap<Integer, PokDengSeatManager> seatMap = table.getSeatMap();
        List<PokDengSeatManager> seats=seatMap.values().stream().collect(Collectors.toList());
        List<PokDengSeatManager> tempList=new ArrayList<>(seats.subList(table.getAskStartSeat(),seats.size()));
        tempList.addAll(seats.subList(0,table.getAskStartSeat()));
        return tempList.iterator();
    }
    /**
     * 机器人进入
     * @param roomManager
     */
    public static void robotEnter(PokDengRoomManager roomManager,int tableId){
        UserMessage robot=RobotUtil.builderRobot(roomManager.getBetArrays()[0]);
        roomManager.getTableManager(tableId).pushUserEE(robotRoomSitDownRecursion(roomManager,tableId,robot), PokDengPushCMDMapType.UserEnterRoom);
    }

    /**
     * 庄家或者机器人 补牌
     * @param roomId
     * @param tableId
     */
    public static int bankerOrRobotAskCard(int roomId,int tableId,int seatNo){
        PokDengTableManager table = PokDengGameManager.getInstance().getController(roomId).getTableManager(tableId);
        PokDengSeatManager seat;
        if(seatNo==table.getBanker().getSeatNo()){
            seat=table.getBanker();
        }else{
            seat=table.getSeatMap().get(seatNo);
        }
        int rd=RandomUtil.randomInt(100);
        if(seat.getUser().getCardVal()==4&&rd<38){
            return -1;
        }
        if(seat.getUser().getCardVal()==5&&rd<56){
            return -1;
        }
        if(seat.getUser().getCardVal()==6&&rd<70){
            return -1;
        }
        if(seat.getUser().getCardVal()==7&&rd<85){
            return -1;
        }
        int card= CardUtil.deal(table.getCardLib(),table.getBanker().getSeatNo(),table.isControl(),seat.getUser().getCards().size());
        seat.getUser().getCards().add(card);
        CardUtil.computeCard(seat.getUser());

        return card;
    }
     /** 系统补牌
     * @param roomId
     * @param tableId
     */
    public static int sysAskCard(int roomId,int tableId,int seatNo){
        PokDengTableManager table = PokDengGameManager.getInstance().getController(roomId).getTableManager(tableId);
        PokDengSeatManager seat;
        if(seatNo==table.getBanker().getSeatNo()){
            seat=table.getBanker();
        }else{
            seat=table.getSeatMap().get(seatNo);
        }
        int card= CardUtil.deal(table.getCardLib(),seatNo,table.isControl(),seat.getUser().getCards().size());
        seat.getUser().getCards().add(card);
        CardUtil.computeCard(seat.getUser());

        return card;
    }

    /**
     * 发送补牌消息
     * @param table
     * @param seat
     */
    public static void sendAskCardMessage(PokDengTableManager table,PokDengSeatManager seat){
        PushOtherAskCardMessage message = new PushOtherAskCardMessage();
        message.setAskCard(seat.getUser().getCards().get(2));
        message.setCard(CardMessage.buildByUser(seat));
        ChessPushMessageUtil.broadcastMessage(table.getOnlineUser().values(), PokDengPushCMDMapType.OtherUserAsdCardMessage.code(),message);
    }

    //---------------  控制庄家补牌 --------------------------

    /**
     * 计算庄家输赢
     * @param tableManager
     * @return
     */
    public static long computeBankerWin(PokDengTableManager tableManager){
        long sysPayment = 0;
        UserMessage banker = tableManager.getBanker().getUser();

        for (PokDengSeatManager seat : tableManager.getSeatMap().values()) {
            if(seat.getUser() != null && seat.getUser().getUserType() != UserType.Robot.code()){
                if(banker.getCardVal() > seat.getUser().getCardVal()){
                    sysPayment += seat.getUser().getBet() * seat.getUser().getCardRate();
                }
                else if(banker.getCardVal() < seat.getUser().getCardVal()){
                    sysPayment -= seat.getUser().getBet() * seat.getUser().getCardRate();
                }
            }
        }
        return sysPayment;
    }

    /**
     * 重置庄家补牌
     * @param tableManager
     */
    public static void resetBankerAsk(PokDengTableManager tableManager){
        UserMessage banker = tableManager.getBanker().getUser();
        //补过牌  退牌
        if(banker.getCards().size() == 3){
            tableManager.getCardLib().add(banker.getCards().get(2));
            banker.getCards().remove(2);
        }
        //洗牌
        Collections.shuffle(tableManager.getCardLib());
    }

    //===================  房间机器人逻辑  ====================================

    /**
     *机器人进入退出
     * 那我走？？
     */
    public static void robotDispose(PokDengRoomManager roomManager,PokDengTableManager tableManager){
        int emptySeatNumber=tableManager.getEmptySeat().size();
        int r=RandomUtil.randomInt(1,11);

        if((PokDengConstantValue.MAX_SEAT-emptySeatNumber)<PokDengConstantValue.ROBOT_ENTER_WITH_EMPTY_SEAT){
            if(r>(PokDengConstantValue.MAX_SEAT-emptySeatNumber)*2){
                TableUtil.robotEnter(roomManager,tableManager.getTableId());
            }
        }else{
            List<PokDengSeatManager> robotSeats = tableManager.getSeatMap().values().stream().filter(seat -> null != seat.getUser() && seat.getUser().getUserType() == UserType.Robot.code()).collect(Collectors.toList());
            if(null==robotSeats||robotSeats.isEmpty()){
                return;
            }
            if(r>emptySeatNumber*2){
                Collections.shuffle(robotSeats);
                tableManager.exitRoom(robotSeats.get(0).getUser().getUserId());
            }
        }
    }
}
